#include "stdafx.h"
#include <pthread.h>
#include <vector>
#include <iostream>

using namespace std;

struct Task
{
	int startRange;
	int endRange;
	int *outputArray;
	int threadIndex;
	bool *confirmArray;

	explicit Task(int start, int end, int index,int *output, bool *boolArray) : startRange(start) , endRange(end), outputArray(output), threadIndex(index), confirmArray(boolArray){}
};

struct OutputStruct
{
	int totalRange;
	int *output;
	bool *confitmArray;
	OutputStruct(int size, int *outputArray, bool *confirmArray) : totalRange(size) , output(outputArray), confitmArray(confirmArray){}
};


class SimpleBagOfTasks
{
	
public:
	pthread_t threads[12];
	int range;
	int *output;
	pthread_t finalWorker;
	bool confimrationArray[12];

	void *TestInner(void *threadNumber)
	{
		//TestStrucct *index = (TestStrucct*)threadNumber;
		//std::cout << "this is the thread number " << index->number << std::endl;
		pthread_exit(NULL);
		return NULL;
	}

	void *ExecuteTask(void *task)
	{
		Task *taskStruct = (Task*) task;
		int *output = taskStruct->outputArray;

		for(int index = taskStruct->startRange; index <= taskStruct->endRange; index++)
		{
			output[index] = index * index;
		}

		taskStruct->confirmArray[taskStruct->threadIndex] = true;
		
		return NULL;
	}

	void *ExecuteOutput(void *range)
	{
		OutputStruct *outputStruct = (OutputStruct *) range;
		int *outputArray = outputStruct->output;

		while(checkBoolArray(outputStruct->confitmArray, 12) == false)
		{
			//loop here and wait
		}

		for(int index = 0; index <outputStruct->totalRange; index++ )
		{
			cout<< outputArray[index] << endl;
		}
	}

	bool checkBoolArray(bool *boolArray, int size)
	{
		for(int boolIndex = 0; boolIndex < size; boolIndex++)
		{
			if(boolArray[boolIndex] == false)
			{
				return false;
			}
		}

		return true;
	}

	SimpleBagOfTasks(int rangeOfNumbers)
	{
		this->range = rangeOfNumbers;
		this->output = new int[rangeOfNumbers];
		vector<Task *> bagOfTasks;
		int numbersPerThreas = rangeOfNumbers / 12;
		int startRange = 0;
		for(int threadIndex = 0; threadIndex < 12; threadIndex ++)
		{
			int currentEnd = startRange + numbersPerThreas - 1;
			Task *currentTask = new Task(startRange, currentEnd,threadIndex, this->output, this->confimrationArray);
			bagOfTasks.push_back(currentTask);
		}

		for(int taskNumber = 0; taskNumber < 12; taskNumber++)
		{
			Task *currentTask = bagOfTasks[taskNumber];
			pthread_create(&threads[taskNumber], NULL, this->ExecuteTask, (void *)currentTask);
		}

		OutputStruct *ouptutStruct = new OutputStruct(rangeOfNumbers, this->output, this->confimrationArray);
		pthread_create(&finalWorker, NULL, &SimpleBagOfTasks::ExecuteOutput, ouptutStruct);
	}
};